﻿using System;

namespace Aeon.Framework
{

/// <summary>
/// Value object for up to three dimensional vector representation.
/// 
/// </summary>
public struct VectorC : IVector
    {
    // --- Attributes:

    private Single x;   // Component X.
    private Single y;   // Component Y.
    private Single z;   // Component Z.

    // --- Properties:

    public Single X { get { return(x); } }
    public Single Y { get { return(y); } }
    public Single Z { get { return(z); } }

    public Double R { get { return(GetPolar().R); } }   // [BUG]
    public Double T { get { return(GetPolar().T); } }   // Missing Z components.

    // --- Constructor:

    /// <summary>
    /// Create vector from 2D cartesian coordinates.
    /// 
    /// </summary>
    /// <param name="x"> X plane component. </param>
    /// <param name="y"> Y plane component. </param>
    public VectorC(Single x, Single y) : this(x,y,0) { }

    /// <summary>
    /// Create vector from 3D cartesian coordinates.
    /// 
    /// </summary>
    /// <param name="x"> X plane component. </param>
    /// <param name="y"> Y plane component. </param>
    /// <param name="z"> Z plane component. </param>
    public VectorC(Single x, Single y, Single z)
        {        
        this.x = x;
        this.y = y;
        this.z = z;
        }

    /// <summary>
    /// Create vector from polar coordinates.
    /// 
    /// </summary>
    /// <param name="module"> Vector magnitude module. </param>
    /// <param name="angles"> Vector direction angle, in radians. </param>
    public VectorC(Double module, Double angle)
        {
        IVector v = new VectorP(module,angle).GetCartesian();
       
        x = v.X;
        y = v.Y;
        z = v.Z;
        }

    // --- Public Methods:

    /// <summary>
    /// Transforms this vector into a unit vector.
    /// 
    /// </summary>
    public void ToUnit()
        {
        IVector unit = GetUnit();

        x = unit.X;
        y = unit.Y;
        z = unit.Z;
        }
    
    /// <summary>
    /// Returns the unitary component of this vector.
    /// Divides by magnitude, square root of the dot product.
    /// 
    /// </summary>
    public IVector GetUnit()
        {
        float magnitude = (float) Math.Pow((Math.Pow(x,2))+(Math.Pow(y,2))+(Math.Pow(z,2)),1/2);

        return(new VectorC(x/magnitude,y/magnitude,z/magnitude));
        }
    
    /// <summary>
    /// Returns the perpendicular normal to this vector.
    /// 
    /// </summary>
    public IVector GetNormal()
        {
        IVector normal;

        // 2D Normal: Negative reciprocal of slope.
        if (z == 0) { normal = new VectorC(-y,x); }
        
        // 3D Normal: [TODO]
        else {
             // You need either one vector and a point or two vectors to use this method.
             // If you are given one vector and one point, you will need to find a second vector using the components of the vector and the ordered triple of the point.
             // If you are only given one vector, come up with another point in the plane so you can find a second vector b.
             // Remember that you can insert a "k" as a scalar to find all parallel vectors to c.

             normal = new VectorC();
             }
        
        return(normal);
        }

    /// <summary>
    /// Returns the 2D polar representation of this vector.
    /// 
    /// </summary>
    public IVector GetPolar()
        {

        return(new VectorP(x,y));
        }

    /// <summary>
    /// Returns the 3D cartesian representation of this vector.
    /// 
    /// </summary>
    public IVector GetCartesian()
        {

        return(this);
        }

    //public Single Angle(IVector vector)
    //    {

    //    } [TODO] Angles between vectors. Normalization+Dot Product+Arc Cosin

    }



}
